<template>
  <q-field ref="QxTime" v-model="timeVal" :class="fieldCls" :disable="disable" :error="!isValid"
           :error-message="placeholder" :readonly="readonly" class="q-field__text" lazy-rules="ondemand" v-bind="$attrs"
           @focus="fieldFocus">
    <template v-slot:control>
      <span v-if="!timeVal" class="placeholder">{{ placeholder }}</span>
      <QxTooltip v-else>{{ timeVal }}</QxTooltip>
    </template>
    <template v-if="!hideIcon || showClearIcon" v-slot:append>
      <q-icon v-if="showClearIcon" class="field-clear-icon cursor-pointer" name="cancel"
              @click.stop="handleClear"></q-icon>
      <q-icon v-if="!hideIcon" name="access_time"></q-icon>
    </template>
    <q-popup-proxy v-model="showPopup" :no-parent-event="readonly || disable" :offset="[0, 5]" anchor="bottom left"
                   breakpoint="0" class="qx-time" no-fouce no-refocus self="top left" transition-hide="jump-up"
                   transition-show="jump-down" @hide="popupBlur">
      <q-scroll-area ref="hourArea" :thumb-style="thumbMenu" :visible="false">
        <q-item v-for="i in hourList" :key="i" v-ripple :active="activeCls(i, 'H')" active-class="time-active-cls"
                clickable dense @click="formatValue(i, 'H')">
          <q-item-section>{{ i }}</q-item-section>
        </q-item>
      </q-scroll-area>
      <q-separator vertical></q-separator>
      <q-scroll-area ref="minArea" :thumb-style="thumbMenu" :visible="false">
        <q-item v-for="i in msList" :key="i" v-ripple :active="activeCls(i, 'M')" active-class="time-active-cls"
                clickable dense @click="formatValue(i, 'M')">
          <q-item-section>{{ i }}</q-item-section>
        </q-item>
      </q-scroll-area>
      <q-separator vertical></q-separator>
      <q-scroll-area ref="secArea" :thumb-style="thumbMenu" :visible="false">
        <q-item v-for="i in msList" :key="i" v-ripple :active="activeCls(i, 'S')" active-class="time-active-cls"
                clickable dense @click="formatValue(i, 'S')">
          <q-item-section>{{ i }}</q-item-section>
        </q-item>
      </q-scroll-area>
    </q-popup-proxy>
  </q-field>
</template>

<script setup>
import QxTooltip from 'components/Global/Tools/QxTooltip.vue'
import { date } from 'quasar'
import { isEmpty } from 'src/utils/utils'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'

const thumbMenu = { width: '.25rem' }
const msList = new Array(60).fill(0).map((_, i) => String(i).padStart(2, '0'))
const hourList = new Array(24).fill(0).map((_, i) => String(i).padStart(2, '0'))

const props = defineProps({
  type: String, disable: Boolean, readonly: Boolean, hideIcon: Boolean, placeholder: String, option: [Array, Function],
  modelValue: [String, Date], lazyRules: [Boolean, String], clearable: { type: Boolean, default: true }
})

const emits = defineEmits(['change', 'update:modelValue'])

const QxTime = ref(null)
const minArea = ref(null)
const secArea = ref(null)
const isValid = ref(true)
const hourArea = ref(null)
const timeVal = ref(void 0)
const showPopup = ref(false)

const showClearIcon = computed(() => {
  const { clearable, disable, readonly } = props
  return readonly || disable || !clearable ? false : !!timeVal.value
})
const fieldCls = computed(() => showPopup.value ? 'q-field--focused q-field--highlighted' : '')
const activeCls = computed(() => {
  return (val, type) => {
    if (!timeVal.value) return
    const timeList = timeVal.value.split(':')
    if (type === 'H') return timeList?.[0] === val
    if (type === 'M') return timeList?.[1] === val
    if (type === 'S') return timeList?.[2] === val
  }
})

const getPosition = (val = '', type) => {
  if (!val) return
  const list = val.split(':')
  if (type === 'H') {
    const indexM = msList.findIndex(el => el === list[1])
    if (minArea.value) minArea.value.setScrollPosition('vertical', indexM * 32 - 96, 0)
    const indexS = msList.findIndex(el => el === list[2])
    if (secArea.value) secArea.value.setScrollPosition('vertical', indexS * 32 - 96, 0)
    return
  }
  if (type === 'M') {
    const indexH = hourList.findIndex(el => el === list[0])
    if (hourArea.value) hourArea.value.setScrollPosition('vertical', indexH * 32 - 96, 0)
    const indexS = msList.findIndex(el => el === list[2])
    if (secArea.value) secArea.value.setScrollPosition('vertical', indexS * 32 - 96, 0)
    return
  }
  if (type === 'S') {
    const indexH = hourList.findIndex(el => el === list[0])
    const indexM = msList.findIndex(el => el === list[1])
    if (hourArea.value) hourArea.value.setScrollPosition('vertical', indexH * 32 - 96, 0)
    if (minArea.value) minArea.value.setScrollPosition('vertical', indexM * 32 - 96, 0)
  }
}

const initValue = () => {
  if (timeVal.value === props.modelValue) return
  if (isEmpty(props.modelValue)) return (timeVal.value = void 0)
  if (typeof props.modelValue === 'object') timeVal.value = date.formatDate(props.modelValue, 'HH:mm:ss')
  else timeVal.value = props.modelValue
}

watch(() => props.modelValue, () => initValue(), { immediate: true })

const handleClear = () => {
  timeVal.value = void 0
  showPopup.value = false
  popupBlur()
}
const popupBlur = () => {
  if (!props.hideIcon) emits('change', timeVal.value || '')
  emits('update:modelValue', timeVal.value || '')
  if (props.lazyRules === 'ondemand') return
  nextTick(() => {
    if (!QxTime.value) return
    QxTime.value.blur()
    isValid.value = QxTime.value.validate()
  })
}
const fieldFocus = () => {
  let timer = setTimeout(() => {
    getPosition(timeVal.value, 'H')
    getPosition(timeVal.value, 'M')
    getPosition(timeVal.value, 'S')
    clearTimeout(timer)
    timer = null
  }, 0)
}
const formatValue = (val, type) => {
  if (type === 'H') {
    if (!timeVal.value) {
      timeVal.value = `${val}:00:00`
      if (minArea.value) minArea.value.setScrollPosition('vertical', 0, 200)
      if (secArea.value) secArea.value.setScrollPosition('vertical', 0, 200)
      if (props.hideIcon) emits('change', timeVal.value)
      return
    }
    timeVal.value = timeVal.value.replace(/^../, val)
    getPosition(timeVal.value, type)
    if (props.hideIcon) emits('change', timeVal.value)
    return
  }
  if (type === 'M') {
    if (!timeVal.value) {
      timeVal.value = `08:${val}:00`
      if (hourArea.value) hourArea.value.setScrollPosition('vertical', 7 * 32, 100)
      if (secArea.value) secArea.value.setScrollPosition('vertical', 0, 200)
      if (props.hideIcon) emits('change', timeVal.value)
      return
    }
    timeVal.value = timeVal.value.replace(/(?<=:)[^:]+(?=:)/, val)
    getPosition(timeVal.value, type)
    if (props.hideIcon) emits('change', timeVal.value)
    return
  }
  if (!timeVal.value) {
    timeVal.value = `08:00:${val}`
    if (hourArea.value) hourArea.value.setScrollPosition('vertical', 7 * 32, 100)
    if (secArea.value) secArea.value.setScrollPosition('vertical', 0, 200)
    if (props.hideIcon) emits('change', timeVal.value)
    return
  }
  timeVal.value = timeVal.value.replace(/..$/, val)
  getPosition(timeVal.value, type, hourList)
  if (props.hideIcon) emits('change', timeVal.value)
}

const scrollHandle = () => {
  if (!showPopup.value || !QxTime.value) return
  const offset = QxTime.value.$el.getBoundingClientRect()
  const innerHeight = window.innerHeight
  if (offset.top > innerHeight || offset.bottom < 0) showPopup.value = false
}
const resizeHandle = () => (showPopup.value = false)
onMounted(() => {
  window.addEventListener('scroll', scrollHandle, true)
  window.addEventListener('resize', resizeHandle, false)
})
onBeforeUnmount(() => {
  window.removeEventListener('scroll', scrollHandle, true)
  window.removeEventListener('resize', resizeHandle, false)
})
</script>